#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <fstream>
#include <sstream>

#include "log.hpp"
using namespace LogModule;

const std::string Sep = "\r\n";
const std::string LineSep = " ";
const std::string HeaderLineSep = ": ";
const std::string BlankLine = Sep;
const std::string defaulthomepage = "wwwroot";
const std::string http_version = "HTTP/1.0";
const std::string page404 = "wwwroot/404.html";
const std::string firstpage = "index.html";

bool ParseOnceLine(std::string &str, std::string *out, const std::string &sep)
{
    // HTTP协议会以"\r\n"为分隔符，所以只要找到"\r\n"
    auto pos = str.find(sep);
    if (pos == std::string::npos)
        return false;
    *out = str.substr(0, pos);
    str.erase(0, pos + Sep.size());
    return true;
}
bool SplitStr(const std::string &header, const std::string &sep, std::string *key, std::string *value)
{
    auto pos = header.find(sep);
    if (pos == std::string::npos)
        return false;
    *key = header.substr(0, pos);
    *value = header.substr(pos + sep.size());
    return true;
}

class HttpRequest
{
public:
    HttpRequest() {}
    ~HttpRequest() {}

    bool IsHasArgs()
    {
        return _isexec;
    }

    // 属性解析后的 K: V
    bool ParseHnadlerLineKV()
    {
        std::string key, value;
        for (auto &header : _req_header)
        {
            if (SplitStr(header, HeaderLineSep, &key, &value))
            {
                _headerkv.insert(std::make_pair(key, value));
            }
        }
        return true;
    }

    bool ParseHnadlerLine(std::string &request_str)
    {
        std::string line;
        while (true)
        {
            bool r = ParseOnceLine(request_str, &line, Sep);
            if (r && !line.empty()) // 解析出一行不带"\r\n"
            {
                _req_header.push_back(line);
            }
            else if (r && line.empty())
            {
                _blank_line = Sep;
                break;
            }
            else
            {
                return false;
            }

            ParseHnadlerLineKV();
        }
        return true;
    }

    // 反序列化
    void Deserialize(std::string &request_str)
    {

        if (ParseOnceLine(request_str, &_req_line, Sep))
        {
            // 读取请求中的详细字段
            ParseReqLine(_req_line, LineSep);
            ParseHnadlerLine(request_str);
            _body = request_str;

            // 分析请求中是否含有参数
            if (_methood == "POST")
            {
                // POST参数在正文部分
                _isexec = true;
                _args = _body;
                _path = _uri;

                LOG(DEBUG, "POST: _path: %s", _path.c_str());
                LOG(DEBUG, "POST: _ars: %s", _args.c_str());
            }
            else if (_methood == "GET")
            {
                auto pos = _uri.find("?");
                if (pos != std::string::npos)
                {
                    // GET参数在uri中
                    _isexec = true;

                    _path = _uri.substr(0, pos);
                    _args = _uri.substr(pos + 1);

                    LOG(DEBUG, "GET: _path: %s", _path.c_str());
                    LOG(DEBUG, "GET: _ars: %s", _args.c_str());
                }
            }
        }
    }

    std::string GetContent(const std::string path)
    {
        // 以二进制方式读取
        std::string content;
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return std::string();
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        return content;

        // ##########################
        //  暂时做法,以文本方式读
        //  std::string content;
        //  std::ifstream in(_uri);
        //  if (!in.is_open())
        //      return std::string();
        //  std::string line;
        //  while (std::getline(in, line))
        //  {
        //      content += line;
        //  }
        //  in.close();
    }

    void Print()
    {
        std::cout << "_methood: " << _methood << std::endl;
        std::cout << "_uri: " << _uri << std::endl;
        std::cout << "_version: " << _version << std::endl;

        for (auto &line : _req_header)
        {
            std::cout << line << "\n"
                      << std::endl;
        }

        for (auto &kv : _headerkv)
        {
            std::cout << kv.first << " # " << kv.second << std::endl;
        }

        std::cout << "_blank_line: " << _blank_line << std::endl;
        std::cout << "_body: " << _body << std::endl;
    }

    std::string Uri()
    {
        return _uri;
    }

    void SetUri(const std::string newuri)
    {
        _uri = newuri;
    }

    std::string Path()
    {
        return _path;
    }

    std::string Args()
    {
        return _args;
    }

    std::string Suffix()
    {
        auto pos = _uri.rfind(".");
        if (pos == std::string::npos)
            return std::string(".html");
        else
            return _uri.substr(pos);
    }

private:
    void ParseReqLine(std::string &req_line, const std::string LineSep)
    {
        (void)LineSep;
        std::stringstream ss(_req_line);
        ss >> _methood >> _uri >> _version;
    }

private:
    std::string _req_line;
    std::vector<std::string> _req_header;
    std::string _blank_line;
    std::string _body;

    // 在反序列化的过程中，细化我们解析出来的字段
    std::string _methood;
    std::string _uri;
    std::string _path;
    std::string _args;
    std::string _version;
    std::unordered_map<std::string, std::string> _headerkv;

    bool _isexec = false;
};

// 对于Http，任何请求都要有应答
class HttpResponse
{
public:
    HttpResponse() : _version(http_version), _blank_line(Sep)
    {
    }
    ~HttpResponse() {}

    void Build(HttpRequest &req)
    {
        std::string uri = defaulthomepage + req.Uri();
        if (uri.back() == '/')
        {
            uri += firstpage;
            req.SetUri(uri);
        }

        _content = req.GetContent(uri);
        if (_content.empty())
        {
            // 用户请求资源不存在
            _status_code = 404;
            req.SetUri(page404);
            _content = req.GetContent(page404);
        }
        else
        {
            _status_code = 200;
        }
        _status_desc = Code2Desc(_status_code);

        if (!_content.empty())
        {
            SetHeader("content-Length", std::to_string(_content.size()));
        }

        std::string mime_type = Suffix2Desc(req.Suffix());
        SetHeader("content-Type", mime_type);

        _body = _content;
    }

    void SetCode(int code)
    {
        _status_code = code;
        _status_desc = Code2Desc(_status_code);
    }

    void SetBody(const std::string &body)
    {
        _body = body;
    }

    void Serialize(std::string *resp)
    {
        for (auto &header : _header_kv)
        {
            _resp_header.push_back(header.first + HeaderLineSep + header.second);
        }
        _resp_line = _version + LineSep + std::to_string(_status_code) + LineSep + LineSep + _status_desc + Sep;

        // 序列化
        *resp = _resp_line;
        for (auto &line : _resp_header)
        {
            *resp += (line + Sep);
        }
        *resp += _blank_line;
        *resp += _body;
    }

    void SetHeader(const std::string &k, const std::string &v)
    {
        _header_kv[k] = v;
    }

private:
    std::string Code2Desc(int code)
    {
        switch (code)
        {
        case 200:
            return "OK";
        case 404:
            return "Not Found";
        case 301:
            return "Moved Permanently";
        case 302:
            return "Found";
        default:
            return "";
        }
    }

    std::string Suffix2Desc(const std::string &suffix)
    {
        if (suffix == ".html")
            return "text/html";
        else if (suffix == ".jpg")
            return "application/x-jpg";
        else
            return "text/html";
    }

private:
    // 必备要素
    std::string _version;
    int _status_code;         // 状态码
    std::string _status_desc; // 状态码描述，与状态码强相关
    std::string _content;
    std::unordered_map<std::string, std::string> _header_kv;

    // 最重要的4部分，构成应答
    std::string _resp_line;
    std::vector<std::string> _resp_header;
    std::string _blank_line;
    std::string _body;
};